﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Ivan.Dm.ChromeRemoteDebugger.Transport {
    public struct MessageHeaderParts {
        public const string ContentLengthEntryKey = "Content-Length";
        public const string ToolEntryKey = "Tool";
        public const string DestintaionEntryKey = "Destination";
        public const string Terminator = "\r\n";
        public const string Separator = ":";
    }

    public class MailformedMessageException : Exception {
        public MailformedMessageException()
            : base() {
        }
    }

    public class Message {
        private Dictionary<string, string> Header { get; set; }
        public string Content { get; protected set; }

        public Message(Dictionary<string, string> header,
                       string content) {
            Header = new Dictionary<string, string>(header);
            Content = content;
            int contentLength = string.IsNullOrEmpty(content) ? 0 : content.Length;
            Header[MessageHeaderParts.ContentLengthEntryKey] = contentLength.ToString();
        }
        
        public string Destination {
            get { return GetHeaderEntry(MessageHeaderParts.DestintaionEntryKey); }
        }

        public string Tool {
            get { return GetHeaderEntry(MessageHeaderParts.ToolEntryKey); }
        }

        private string GetHeaderEntry(string key) {
            if (Header.ContainsKey(key))
                return Header[key];
            return null;
        }
      
        private static Dictionary<string, string> GetMessageHeader(StreamReader reader) {
            var header = new Dictionary<string, string>();
            var headerLine = string.Empty;
            string[] keyValue = null;
            while (true) {
                headerLine = reader.ReadLine();
                if (headerLine == null)
                    throw new MailformedMessageException();
                if (headerLine.Length == 0)
                    break;
                keyValue = headerLine.Split(MessageHeaderParts.Separator.ToCharArray());
                if (keyValue.Length != 2)
                    throw new MailformedMessageException();
                header.Add(keyValue[0], keyValue[1].Trim());
            }
            return header;
        }

        private static string GetMessageContent(StreamReader reader, 
                                                Dictionary<string, string> header) {
            int contentLength = 0;
            int readerResult = -1;
            var contentBuilder = new StringBuilder();
            string strContentLength = header.ContainsKey(MessageHeaderParts.ContentLengthEntryKey) ?
                header[MessageHeaderParts.ContentLengthEntryKey] : "0";
            if (!int.TryParse(strContentLength, out contentLength))
                throw new MailformedMessageException();
            for (int i = 0; i < contentLength; i++) {
                readerResult = reader.Read();
                if (readerResult == -1)
                    throw new MailformedMessageException();
                contentBuilder.Append((char)readerResult);
            }
            return contentBuilder.ToString().Trim();
        }

        public static Message ReadFromStream(StreamReader streamReader) {
            Dictionary<string, string> header = null;
            string content = string.Empty;
            try {
                header = GetMessageHeader(streamReader);
                content = GetMessageContent(streamReader, header);
            }
            catch (MailformedMessageException) {
                return null;
            }
            return new Message(header, content);
        }

        public void WriteToStream(StreamWriter writer) {
            var messageBuilder = new StringBuilder();
            foreach (KeyValuePair<string, string> headerEntry in Header) {
                if (string.IsNullOrEmpty(headerEntry.Value))
                    continue;
                messageBuilder.Append(headerEntry.Key);
                messageBuilder.Append(MessageHeaderParts.Separator);
                messageBuilder.Append(headerEntry.Value);
                messageBuilder.Append(MessageHeaderParts.Terminator);
            }
            messageBuilder.Append(MessageHeaderParts.Terminator);
            if (!string.IsNullOrEmpty(Content))
                messageBuilder.Append(Content);
            writer.Write(messageBuilder.ToString());
            writer.Flush();
        }

    }
}
